﻿// See https://aka.ms/new-console-template for more information
using CommonLib;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Text;

Console.WriteLine("AppPublisher已启动");

// 参照学习的blog地址  https://blog.csdn.net/qq_45173404/article/details/121687489
// RabbitMQ 管理地址：http://localhost:15672/#/exchanges

#region 简单模式

/*
 * 简单模式 Hello world
 * 一个生产者、一个消费者、一个队列
 */
//Console.WriteLine("Hello, World!");
/*
//var factory = new ConnectionFactory();
//factory.HostName = "localhost";
//factory.Port = 5672;
//factory.UserName = "wja";
//factory.Password = "123456";
//factory.DispatchConsumersAsync = true;
string exchangeName = "exchange1";
string eventName = "MyEvent";
//var connection = factory.CreateConnection();
//var channel = connection.CreateModel();

var channel = RabbitMQUtil.CreateChannel();

while (true)
{
    var properties = channel.CreateBasicProperties();
    string msg = DateTime.Now.ToString("yyyy-MM-dd") + "发送了消息";
    properties.DeliveryMode = 2;
    channel.ExchangeDeclare(exchange: exchangeName, type: "direct");
    var body = Encoding.UTF8.GetBytes(msg);
    channel.BasicPublish(exchange: exchangeName, routingKey: eventName, mandatory: true, basicProperties: properties, body);

    Console.WriteLine("发布了消息：" + msg);
    Thread.Sleep(1000);
}
*/

#endregion


#region 工作模式

/*
 * 工作模式：work queues
 * 一个生产者、多个消费者、一个队列
 * 主要作用是避免排队等待
 * RabbitMQ采用轮询方式，也就是如果有两个消费者会轮流给每一个分任务
 */
/*
 * 工作模式的生产者声明队列 发布消息
 * 消费者 声明回调消费消息即可
 */
//var queueName = "workQueues";
//// 获取channel
//var workChannel = RabbitMQUtil.CreateChannel();
//// 声明队列
//workChannel.QueueDeclare(queue: queueName, true, false, false, null);
//// 发送消息
//int index = 1;
//while (true)
//{
//    var msg = "这个是测试RabbitMQ工作模式的消息"+index;
//    var body = Encoding.UTF8.GetBytes(msg);
//    workChannel.BasicPublish("", queueName, true, null, body);
//    index++;
//    Console.WriteLine("发布了消息：" + msg);
//    Thread.Sleep(1000);
//}

#endregion


#region Fanout 发布订阅模式

/*
 * 发布订阅模式中发布在只把消息发送给交换机即可，它不需要知道消息最终发送到那个队列了。
 * 交换机会绑定队列，队列会绑定消费者。其实这些是在消费者中设置的
 * 
 */

//// 1 创建信道 channel
//var channel = RabbitMQUtil.CreateChannel();

//// 2 声明交换机 
//channel.ExchangeDeclare("logs", type: "fanout");

//// 3 发布消息
//for (int i = 0; i < 100; i++)
//{
//    var msg = "fanout 模式消息" + i;
//    var body = Encoding.UTF8.GetBytes(msg);
//    channel.BasicPublish("logs","",false,null,body);
//    Console.WriteLine("发布了消息："+msg);
//}
//Console.ReadKey();

#endregion

#region Direct 路由模式

/*
 * 需要先启动消费端程序，然后启动发布端，因为消费端有交换机和队列到绑定
 */

//string exchangeName = "direct-logs";

//// 1 创建信道 channel
//var channel = RabbitMQUtil.CreateChannel();

//// 2 声明交换机
//channel.ExchangeDeclare(exchangeName, "direct",true,false,null);

//// 3 发送消息
//Dictionary<string, string> messageMap = new Dictionary<string, string>();
//messageMap.Add("info", "普通 info 消息");
//messageMap.Add("warning", "警告 warning 信息");
//messageMap.Add("error", "警告 error 信息");
//messageMap.Add("debug", "警告 debug 信息");

//foreach (string key in messageMap.Keys)
//{
//    string value = messageMap[key];
//    var body = Encoding.UTF8.GetBytes(value);
//    channel.BasicPublish(exchangeName, key, null, body);
//    Console.WriteLine("消息发送完毕"+value);
//}
#endregion

#region Topic 模式

//string exchangeName = "topic_logs";

//// 1 创建信到 channel
//var channel = RabbitMQUtil.CreateChannel();

//// 2 声明交换机 
//channel.ExchangeDeclare(exchangeName, "topic");

//// 3 发送消息
//Dictionary<string,string> messageMap = new Dictionary<string,string>();
//messageMap.Add("quick.orange.rabbit", "被队列Q1 Q2 接受到");
//messageMap.Add("lazy.orange.elephant", "被队列Q1 Q2 接受到");
//messageMap.Add("quick.orange.fox", "被队列Q1 接受到");
//messageMap.Add("lazy.brown.fox", "被队列Q2 接受到");
//messageMap.Add("lazy.brown.rabbit", "虽然满足两个绑定但只被队列 Q2 接受到");
//messageMap.Add("quick.brown.fox", "不匹配任何绑定不会被任何队列接收到会被丢弃");
//messageMap.Add("quick.orange.male.rabbit", "是四个单词不会匹配到任何绑定会被丢弃掉");
//messageMap.Add("lazy.orange.male.rabbit", "是四个单词匹配 会被 Q2 接受到");

//foreach (var key in messageMap.Keys)
//{
//    var value = messageMap[key];
//    var body = Encoding.UTF8.GetBytes(value);
//    channel.BasicPublish(exchangeName,key,null,body);
//    Console.WriteLine("消息发送完毕"+value);
//}
#endregion

#region 测试预设值
//// 测试预设值
//string queueName = "test_prefetch";

//// 1 创建信道 channel
//var channel = RabbitMQUtil.CreateChannel();

//// 消息发布确认
//// 发布确认机制有三种策略：单个确认发布、批量确认发布、异步确认发布。
//channel.ConfirmSelect();

//// 2 发送消息
//channel.QueueDeclare(queueName,false,false,false,null);

//for (int i = 0; i < 10; i++)
//{
//    var msg = "测试Prefetch消息" + i;
//    var body = Encoding.UTF8.GetBytes(msg);
//    channel.BasicPublish("",queueName,null,body);
//    Console.WriteLine("消息发送完毕"+msg);
//} 
#endregion


#region 发布确认 
//// 发布确认
//string queueName = "test_confirm";

//// 1 创建信道 channel
//var channel = RabbitMQUtil.CreateChannel();

//// 消息发布确认
//// 发布确认机制有三种策略：单个确认发布、批量确认发布、异步确认发布。
//channel.ConfirmSelect();

//Stopwatch stopwatch = Stopwatch.StartNew();

//// 2 发送消息
//channel.QueueDeclare(queueName, false, false, false, null);

//for (int i = 0; i < 10; i++)
//{
//    var msg = "测试发布确认消息" + i;
//    var body = Encoding.UTF8.GetBytes(msg);
//    channel.BasicPublish("", queueName, null, body);
//    // 单个消息确认
//    bool flag = channel.WaitForConfirms();
//    if(flag) Console.WriteLine($"消息{i}发布成功");
//}

//stopwatch.Stop();
//Console.WriteLine("发布了10条消息，耗时："+stopwatch.ElapsedMilliseconds); 
#endregion

#region 批量发布确认

//string queueName = "test_confirm";

//// 1 创建信道 channel
//var channel = RabbitMQUtil.CreateChannel();

//// 消息发布确认
//// 发布确认机制有三种策略：单个确认发布、批量确认发布、异步确认发布。
//channel.ConfirmSelect();

//// 批量大小
//int batchSize = 5;
//// 未确认消息数
//int nonConfirmMesNum = 0;

//Stopwatch stopwatch = Stopwatch.StartNew();

//// 2 发送消息
//channel.QueueDeclare(queueName, false, false, false, null);

//for (int i = 0; i < 10; i++)
//{
//    var msg = "测试发布批量确认消息" + i;
//    var body = Encoding.UTF8.GetBytes(msg);
//    channel.BasicPublish("", queueName, null, body);
//    nonConfirmMesNum++;
//    if (nonConfirmMesNum==batchSize)
//    {
//        // 批量消息确认
//        bool flag = channel.WaitForConfirms();
//        if (flag) Console.WriteLine($"消息{i}与之前的{batchSize}条发布成功");
//        nonConfirmMesNum = 0;
//    }
//}

//// 为了确保还有剩余没有确认的消息 再次确认
//if (nonConfirmMesNum > 0)
//{
//    channel.WaitForConfirms();
//}

//stopwatch.Stop();
//Console.WriteLine("发布了10条消息，耗时：" + stopwatch.ElapsedMilliseconds);


#endregion

#region 异步确认

//string queueName = "test_confirm";

//// 1 创建信道 channel
//var channel = RabbitMQUtil.CreateChannel();

//// 消息发布确认
//// 发布确认机制有三种策略：单个确认发布、批量确认发布、异步确认发布。
//channel.ConfirmSelect();

//// 消息大小
//int messageCount = 10;

//Stopwatch stopwatch = Stopwatch.StartNew();

//// 2 发送消息
//channel.QueueDeclare(queueName, false, false, false, null);

//// 成功回调函数
//channel.BasicAcks += (sender, args) =>
//{
//    Console.WriteLine($"消息确认成功 - DeliveryTag: {args.DeliveryTag}, Multiple: {args.Multiple}");
//    // 这里可以执行成功后的业务逻辑
//};

//// 失败回调函数
//channel.BasicNacks += (sender, args) =>
//{
//    Console.WriteLine($"消息确认失败 - DeliveryTag: {args.DeliveryTag}, Multiple: {args.Multiple}");
//    // 这里可以执行失败处理逻辑，如重试、记录日志等
//};

//// 当消息无法路由时返回
//channel.BasicReturn += (sender, args) =>
//{
//    Console.WriteLine($"消息无法路由 - ReplyCode: {args.ReplyCode}, ReplyText: {args.ReplyText}");
//    var returnedMessage = Encoding.UTF8.GetString(args.Body.ToArray());
//    Console.WriteLine($"返回的消息: {returnedMessage}");
//};

//for (int i = 0; i < 10; i++)
//{
//    var msg = "测试发布异步确认消息" + i;
//    var body = Encoding.UTF8.GetBytes(msg);
//    channel.BasicPublish("", queueName,true, null, body);
//}

//stopwatch.Stop();
//Console.WriteLine("发布了10条消息，耗时：" + stopwatch.ElapsedMilliseconds);


#endregion

#region 消息TTL过期

/*
 * TTL过期就是消息中指定的时间内没有被消费就转移到（死信队列）一个专门的队列中
 * 使用场景：消费者下单后未在规定的时间内付款。
 * 我们需要把这个商品的状态改为未销售
 * 
 * 测试需要先启动 测试消费者1 声明好队列和交换机
 * 2 启动发布者，发布消息
 * 3 等待10秒后可以看到消息会从正常队列转移到死信队列中
 * 4 启动消费者2 消费死信队列中的消息
 */

//// 普通交换机的名称
//string normalExchange = "normal_exchange";

//// 创建信道 channel
//var channel = RabbitMQUtil.CreateChannel();

//// 声明普通交换机
//channel.ExchangeDeclare(normalExchange, "direct");

//// 设置消息TTL过期时间为10秒
//var properties = channel.CreateBasicProperties();
//properties.Expiration = "10000";
//properties.Persistent = true;

//// 发送10条消息
//for (int i = 0; i < 10; i++)
//{
//    var msg = "测试TTL过期" + i;
//    var body = Encoding.UTF8.GetBytes(msg);
//    channel.BasicPublish(normalExchange,"zhangsan",properties,body);
//    Console.WriteLine("生产者发送消息："+msg);
//}

#endregion

#region 队列达到最大长度

// 普通交换机的名称
string normalExchange = "normal_exchange";

// 创建信道 channel
var channel = RabbitMQUtil.CreateChannel();

// 声明普通交换机
channel.ExchangeDeclare(normalExchange, "direct");

// 发送10条消息
for (int i = 0; i < 10; i++)
{
    //var msg = "测试队列达到最大长度" + i;
    var msg = "测试消息被拒" + i;
    var body = Encoding.UTF8.GetBytes(msg);
    channel.BasicPublish(normalExchange, "zhangsan", null, body);
    Console.WriteLine("生产者发送消息：" + msg);
}

#endregion



Console.ReadLine();

